package com.ben.multiple.util;

import lombok.extern.log4j.Log4j2;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Arrays;
import java.util.Enumeration;

/**
 * ip 工具
 *
 * @author ben
 * @date 2019/8/30
 */
@Log4j2
public final class IpUtils {
    private IpUtils() {
    }

    /**
     * 字符串分隔符
     */
    private final static String SEPARATOR = ",";
    private final static String HEADER_UNKNOWN = "unKnown";

    /**
     * 获取本地ip
     *
     * @return InetAddress
     */
    public static InetAddress getLocalHostAddress() {
        InetAddress candidateAddress = null;
        try {
            // 遍历所有的网络接口
            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // 在所有的接口下再遍历IP
                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {
                        // 排除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // 如果是site-local地址，就是它了
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现，先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案
            return InetAddress.getLocalHost();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("ip获取失败", e);
        }
        return candidateAddress;
    }

    public static String getLocalHostAddressStr() {
        InetAddress localHostAddress = getLocalHostAddress();
        return localHostAddress == null ? null : localHostAddress.toString().replace("/", "");
    }

    /**
     * @param request      获取请求的ip
     * @param otherHeaders 其它 ip 的请求头
     * @return String
     */
    public static String getRemoteHostIp(HttpServletRequest request, String... otherHeaders) {
        String[] headers = new String[]{"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
        if (otherHeaders != null && otherHeaders.length != 0) {
            headers = Arrays.copyOf(headers, headers.length + otherHeaders.length);
            System.arraycopy(otherHeaders, 0, headers, headers.length - otherHeaders.length, otherHeaders.length);
        }
        String ip;
        //依次遍历请求头，获取ip
        for (String header : headers) {
            ip = request.getHeader(header);
            if (!isUnknown(ip)) {
                return getMultistageReverseProxyIp(ip);
            }
        }
        ip = request.getRemoteAddr();
        return getMultistageReverseProxyIp(ip);
    }

    private static String getMultistageReverseProxyIp(String ip) {
        if (ip != null) {
            String[] ips = ip.trim().split(SEPARATOR);
            for (String subIp : ips) {
                if (!isUnknown(subIp)) {
                    return subIp;
                }
            }
        }
        return ip;
    }

    /**
     * @param ip 空或未知校验
     * @return Boolean
     */
    private static Boolean isUnknown(String ip) {
        return ip == null || "".equals(ip) || HEADER_UNKNOWN.equalsIgnoreCase(ip);
    }
}
